package com.xm.component.easyexport;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@SuppressWarnings("ALL")
@Aspect
@Component
@Slf4j
public class ExportAop {

    @Around("@annotation(com.xm.component.easyexport.EasyExcel)")
    public <P> Object export(ProceedingJoinPoint pjp) throws Throwable {
        ServletRequestAttributes requestAttributes = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes()));
        HttpServletRequest request = requestAttributes.getRequest();
        if (!request.getHeader("easyexport").equalsIgnoreCase("true")) {
            return pjp.proceed();
        }
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        EasyExcel annotation = method.getAnnotation(EasyExcel.class);
        final Converter converter = annotation.resultConverterClass().newInstance();
        ExcelWriter excelWriter = null;
        try {
            // 这里 需要指定写用哪个class去写
            HttpServletResponse response = requestAttributes.getResponse();
            assert response != null;
            Class<?> modelClass = annotation.modelClass();
            excelWriter = com.alibaba.excel.EasyExcel.write(response.getOutputStream(), modelClass).build();
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = URLEncoder.encode(annotation.filename(), "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            // 这里注意 如果同一个sheet只要创建一次
            WriteSheet writeSheet = com.alibaba.excel.EasyExcel.writerSheet(annotation.sheetName()).build();

            if (converter instanceof PageConverter) {
                PageConverter pageConverter = (PageConverter) converter;
                Object[] args = pjp.getArgs();
                List<PageArgsSetter> argList = Stream.of(args).filter(e -> e instanceof PageArgsSetter)
                        .map(e -> (PageArgsSetter) e).collect(Collectors.toList());
                for (int pageIndex = 1; ; pageIndex++) {
                    for (PageArgsSetter pageArgsSetter : argList) {
                        pageArgsSetter.consume(pageIndex, annotation.pageSize());
                    }
                    Object result = pjp.proceed(args);
                    List<?> data = pageConverter.convert(modelClass, result);
                    excelWriter.write(data, writeSheet);
                    //判断是否终止分页
                    if (!pageConverter.hasNext(result)) {
                        break;
                    }
                    if (data.size() < annotation.pageSize()) {
                        break;
                    }
                }
            } else {
                Object result = pjp.proceed();
                List<?> data = converter.convert(modelClass, result);
                excelWriter.write(data, writeSheet);
            }
            return null;
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }
}
